import { Action } from "@/mdesign-lib/mdesign-app.umd.js";
import { MenuItem } from "@/mdesign-lib/mdesign-app.umd.js";
import { Shape, GraphModel, ShapeKey, ShapeType, ConnectModel } from "@/mdesign-lib/mdesign-graph.umd.js";
import { SiderBarItem } from "@/config/types";
import { CreateExchangeWindow } from "../customWindows/createExchange";
import { archService } from "@/mdesign-lib/mdesign-app.umd.js";
import { ConnectShapeDto } from "@/mdesign-lib/mdesign-app.umd.js";
import { ApiCode } from "@/mdesign-lib/mdesign-app.umd.js";
import { shapeService } from "@/mdesign-lib/mdesign-app.umd.js";
import { GraphNode } from "@/mdesign-lib/mdesign-app.umd.js";
import { ActionKey } from "@/mdesign-lib/mdesign-app.umd.js";
import { DiagramTableEditor, MTableRow } from "@/mdesign-lib/mdesign-app.umd.js";
import { sleepUntil } from "@/util/common";

export class CreateExchangeAction extends Action {
  keyName = "createExchange" as ActionKey;
  desc = "createExchange";

  async run({
    graph,
    shape,
    siderbarItem,
    conveyedId
  }: {
    graph: GraphModel;
    shape: Shape;
    siderbarItem: SiderBarItem;
    conveyedId?: string;
  }): Promise<any> {
    const projectId = app.activeProject!.config.id;
    if (shape.shapeType === ShapeType.Edge) {
      let relationId = shape.modelId;
      await CreateExchangeWindow.popup(
        {
          projectId,
          relationId,
          stereotype: siderbarItem.modelId || "",
          conveyedId
        },
        async result => {
          if (result.success) {
            const itemflowData = result.itemflowData;
            if (itemflowData) {
              Object.assign(itemflowData, { payload: siderbarItem.payload });
              await archService.createExchange(itemflowData);
            }
            CreateExchangeWindow.done();
          }
        }
      );

      return;
    }
    const edgeOpt = await shapeService.getEdgeShapeOption(
      projectId,
      siderbarItem.modelId as string,
      siderbarItem.operation,
      siderbarItem.shapeKey as ShapeKey
    );
    if (!edgeOpt) {
      return;
    }
    graph.connectModel.startConnect(
      shape,
      edgeOpt,
      siderbarItem.showData?.siderBarkey || edgeOpt.shapeKey,
      undefined,
      [siderbarItem.modelId as string],
      this.endConnectCallBack
    );
  }

  async onShapeMenuClick(graph: GraphModel, shape: Shape, menuItem: MenuItem) {
    if (menuItem.typeName) {
      menuItem.showData = {
        siderBarkey: menuItem.typeName
      };
    }
    const conveyedId = menuItem.conveyedId as string;

    const siderbarItem = menuItem as unknown as SiderBarItem;
    await this.run({ graph, shape, siderbarItem, conveyedId });
    graph.popMenuModel.freshMenuItems();
  }

  onTreeMenuClick(graphNode: GraphNode, params: any) {
    this.onMatrixClick(params);
  }

  onMatrixClick(params?: any) {
    return CreateExchangeWindow.popup(
      {
        projectId: app.activeProject!.config.id,
        stereotype: params.modelType,
        firstEndId: params.sourceId,
        secondEndId: params.targetId
      },
      async result => {
        if (result.success) {
          const itemflowData = result.itemflowData;
          if (itemflowData) {
            await archService.createExchange(itemflowData);
          }
          CreateExchangeWindow.done();
        }
      }
    );
  }

  async onTableToolbarClick(tableEditor: DiagramTableEditor) {
    const projectId = app.activeProject!.config.id;
    const tableBaseConfig = tableEditor.getTableBaseConfig();
    await CreateExchangeWindow.popup(
      {
        projectId,
        relationId: "",
        stereotype: tableBaseConfig?.addElementParams?.exchangeType || "",
        showSendingAndReceiving: true
      },
      async result => {
        if (result.success) {
          const itemflowData = result.itemflowData;
          let res;
          if (itemflowData) {
            Object.assign(itemflowData);
            res = await archService.createExchange(itemflowData);
          }
          CreateExchangeWindow.done();

          let modelId = res.instanceId as string;

          if (!modelId) return;

          // 手动插入骨架并加载行数据
          const rowData: MTableRow = {
            cells: {},
            id: modelId,
            index: 0,
            height: 28,
            top: 0
          };
          tableEditor.tableModel.addRowDatas([rowData]);
          if (!rowData.loading && !rowData.loaded) {
            await tableEditor.freshRows([rowData]);
          }
          if (!res || !res.instanceId) return;
          const row = tableEditor.tableModel.rowMap.get(modelId);
          if (!row) return;
          await sleepUntil(() => row.loaded).then(() => {
            setTimeout(() => {
              tableEditor.tableModel.scrollRowIntoView(modelId);
              tableEditor.tableModel.setSelectedRows([row]);
              tableEditor.tableModel.clearCells();
              tableEditor.tableModel.selectAllCellOfRow(row);
            }, 10);
          });
        }
      }
    );
  }

  async endConnectCallBack(connectModel: ConnectModel) {
    if (connectModel.validConnect) {
      let waypoint = connectModel.previewEdge!.waypoint;
      const projectId = app.activeProject!.config.id;
      const shapeData: ConnectShapeDto = {
        waypoint: waypoint,
        projectId: projectId,
        diagramId: connectModel.sourceShape!.diagramId,
        sourceShapeId: connectModel.sourceShape!.id,
        targetShapeId: connectModel.targetShape?.id,
        edgeKey: connectModel.edgeType as any,
        payload: {}
      };
      const stereotype = connectModel.applyStereotypes?.[0] || "";
      let baseStereotype = "";
      if (stereotype) {
        baseStereotype = await archService.getStereotypeBaseType(projectId, stereotype);
      }
      if (stereotype === "UAF::Strategic::Connectivity::StrategicExchange") {
        baseStereotype = "UAF::Strategic::Connectivity::StrategicExchange";
      }
      await CreateExchangeWindow.popup(
        {
          projectId: projectId,
          isDirection: true,
          firstEndId: connectModel.sourceShape!.modelId,
          secondEndId: connectModel.targetShape!.modelId,
          stereotype: baseStereotype
        },
        async itemflowRes => {
          if (itemflowRes.success) {
            itemflowRes.itemflowData.applyStereotypes = [stereotype];
            shapeData.payload = { itemflowData: itemflowRes.itemflowData };
            const res = await shapeService.connectShape(shapeData, false).catch(err => err);
            if (res.code !== ApiCode.SUCCESS) {
              app.$notify({
                type: "error",
                message: res.message,
                title: "错误"
              });
            }
          }
          CreateExchangeWindow.done();
          connectModel.clear();
        }
      );
    }
    connectModel.clear();
  }
}
